package com.project.study.farming.base.service.impl;

import cn.hutool.core.util.StrUtil;
import com.project.study.farming.base.entity.dto.*;
import com.project.study.farming.base.entity.po.*;
import com.project.study.farming.base.manager.ConsumerManager;
import com.project.study.farming.base.manager.GuanliManager;
import com.project.study.farming.base.service.GuanLiMainService;
import com.project.study.farming.common.constant.Constant;
import com.project.study.farming.common.entity.dto.Page;
import com.project.study.farming.common.entity.dto.TcCodeDto;
import com.project.study.farming.common.entity.po.UserPo;
import com.project.study.farming.common.exception.ServiceException;
import com.project.study.farming.common.mapper.BaseMapper;
import com.project.study.farming.common.utils.BeanMapper;
import com.project.study.farming.common.utils.CommonUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.ModelAndView;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 管理员主要业务实现类
 * @since 2020-05-01
 */
@Service
@Transactional
public class GuanLiMainServiceImpl implements GuanLiMainService {

    @Autowired
    private ConsumerManager consumerManager;

    @Autowired
    private GuanliManager guanliManager;

    @Autowired
    private BeanMapper beanMapper;

    @Autowired
    private BaseMapper baseMapper;

    @Override
    public ModelAndView glMain(){
        return CommonUtil.success("glMain.html", null);
    }

    @Override
    public ModelAndView uploadCropsPage() {
        Map<String, Object> map = new HashMap<>();
        map.put("types", this.consumerManager.getTypes());
        return CommonUtil.success("glabout.html", map);
    }

    @Override
    public ModelAndView uploadCrops(UploadCropsDto dto) {
        this.guanliManager.upload(dto);
        return uploadCropsPage();
    }

    @Override
    public ModelAndView searchAudit(Integer pageNum, Integer bigType, Integer cropId, Integer auditStatus) {
        Map<String, Object> res = new HashMap<>(8);
        List<AuditPageDto> list = this.guanliManager.searchAudit(bigType, cropId, auditStatus);
        List<TcCodeDto> dic = this.baseMapper.getTcCode(105);
        res.put("bigTypeDic", dic);
        res.put("types",  this.beanMapper.selectList(CropsPo.class));
        res.put("auditDic", this.baseMapper.getTcCode(102));
        list = list.stream().peek(po -> po.setType(CommonUtil.getTcCodeValue(dic, Integer.parseInt(po.getType())))).collect(Collectors.toList());
        res.put("audits", Objects.isNull(pageNum) ? new Page<>(list) : new Page<>(pageNum, list));
        res.put("bigType", bigType);
        res.put("cropId", cropId);
        res.put("auditStatus", auditStatus);
        return CommonUtil.success("glcheck.html", res);
    }

    @Override
    public ModelAndView auditResult(String id, Integer status, Integer pageNum) {
        AuditPo auditPo = this.beanMapper.selectOne(AuditPo.class, String.format("id = %s", id));
        Double count = auditPo.getCount();
        UserPo user = CommonUtil.getUser();
        LocalDateTime now = LocalDateTime.now();
        int use = 104001;
        if(102002 == status){
            if(auditPo.getType().equals(105001)){
                AreaPo areaPo = this.beanMapper.selectOne(AreaPo.class, String.format("id = %d", auditPo.getAreaId()));
                Double enableSize = areaPo.getEnableSize();
                if(count > enableSize){
                    throw new ServiceException(String.format("无法审批通过，因为申请资源（%s）大于可用资源（%s）", count, enableSize));
                }else if(count.equals(enableSize)){
                    use = 104002;
                }
                areaPo.setEnableSize(enableSize - count);
                areaPo.setUsedSize(areaPo.getUsedSize() + count);
                areaPo.setUpdateTime(now);
                areaPo.setUpdateBy(user.getUsername());
                areaPo.setUseStatus(String.valueOf(use));
                this.beanMapper.updateById(areaPo);
            }else if(auditPo.getType().equals(105002)){
                MedicinePo medicine = this.beanMapper.selectOne(MedicinePo.class, String.format("id = %d", auditPo.getCropsId()));
                Double enableSize = medicine.getEnableSize();
                if(count > enableSize){
                    throw new ServiceException(String.format("无法审批通过，因为申请资源（%s）大于可用资源（%s）", count, enableSize));
                }else if(count.equals(enableSize)){
                    use = 104002;
                }
                medicine.setEnableSize(enableSize - count);
                medicine.setUsedSize(count + medicine.getUsedSize());
                medicine.setUseStatus(String.valueOf(use));
                medicine.setUpdateTime(now);
                medicine.setUpdateBy(user.getUsername());
                this.beanMapper.updateById(medicine);
                PlantDetailPo medicineDetail = this.beanMapper.selectOne(PlantDetailPo.class, String.format("audit_id = %d", auditPo.getId()));
                medicineDetail.setMediSize(auditPo.getCount());
                medicineDetail.setMedicineId(auditPo.getCropsId());
                this.beanMapper.updateById(medicineDetail);
            }
        }
        auditPo.setAuditStatus(status);
        auditPo.setAuditTime(now);
        auditPo.setAuditId(user.getId());
        auditPo.setUpdateTime(now);
        auditPo.setUpdateBy(user.getUsername());
        this.beanMapper.updateById(auditPo);
        return this.searchAudit(pageNum,  null, null, null);
    }

    @Override
    public ModelAndView deleteRes(String id, Integer pageNum) {
        this.guanliManager.deleteRes(id);
        return this.searchAudit(pageNum, null, null, null);
    }

    @Override
    public ModelAndView areaPage(Integer pageNum) {
        List<AreaPo> list = this.beanMapper.selectList(AreaPo.class, "is_delete = 103001");
        List<TcCodeDto> dic = this.baseMapper.getTcCode(104);
        List<CropAreaPo> cropAreas = this.beanMapper.selectList(CropAreaPo.class);
        List<AreaPageDto> res = new ArrayList<>();
        list.forEach(po -> {
            AreaPageDto dto = new AreaPageDto();
            po.setUseStatus(CommonUtil.getTcCodeValue(dic, Integer.parseInt(po.getUseStatus())));
            String s = cropAreas.stream().filter(ca -> ca.getAreaId().equals(po.getId())).map(p -> String.valueOf(p.getCropId())).collect(Collectors.joining(","));
            List<CropsPo> crops = StrUtil.isBlank(s) ? new ArrayList<>() : this.beanMapper.selectList(CropsPo.class, String.format("id in (%s)", s));
            BeanUtils.copyProperties(po, dto);
            dto.setCrops(crops.isEmpty() ? "" : crops.stream().map(CropsPo :: getName).collect(Collectors.joining(",")));
            res.add(dto);
        });
        return CommonUtil.successSelect("glarea.html", res, pageNum);
    }

    @Override
    public ModelAndView deleteArea(String id, Integer pageNum) {
        this.baseMapper.update(String.format("update tm_area set is_delete = 103002 where id = %s", id));
        return this.areaPage(pageNum);
    }

    @Override
    public ModelAndView editArea(String id) {
        Map<String, Object> res = new HashMap<>();
        res.put("types", this.baseMapper.getTcCode(104));
        AreaPo areaPo = StrUtil.isBlank(id) ? new AreaPo() : this.beanMapper.selectOne(AreaPo.class, String.format("id = %s", id));
        res.put("target", areaPo);
        List<CropsPo> cropsPo = this.beanMapper.selectList(CropsPo.class);
        List<CropAreaPo> areas = StrUtil.isBlank(id) ? null : this.beanMapper.selectList(CropAreaPo.class, String.format("area_id = %s", id));
        List<CropAreaDto> cropAreaDtos = cropsPo.stream().filter(crop ->
            Objects.isNull(areas) || areas.stream().noneMatch(area -> area.getCropId().equals(crop.getId()))).map(crop -> {
            Integer cId = crop.getId();
            CropAreaDto dto = new CropAreaDto();
            dto.setCropId(cId);
            dto.setCropName(crop.getName());
            return dto;
        }).collect(Collectors.toList());
        res.put("cropArea", cropAreaDtos);
        return CommonUtil.success("editArea.html", res);
    }

    @Override
    public ModelAndView saveArea(AreaPageDto dto) {
        AreaPo areaPo = new AreaPo();
        BeanUtils.copyProperties(dto, areaPo);
        UserPo userPo = CommonUtil.getUser();
        LocalDateTime now = LocalDateTime.now();
        areaPo.setIsDelete(103001);
        Double size = areaPo.getSize();
        if(Objects.isNull(areaPo.getId())){
            areaPo.setEnableSize(areaPo.getSize());
            areaPo.setUsedSize(0.0);
            areaPo.setCreateBy(userPo.getUsername());
            areaPo.setCreateTime(now);
            this.beanMapper.insert(areaPo);
        }else{
            AreaPo havPo = this.beanMapper.selectOne(AreaPo.class, String.format("id = %s", areaPo.getId()));
            havPo.setSize(size);
            havPo.setEnableSize(size - havPo.getUsedSize());
            havPo.setUpdateBy(userPo.getUsername());
            havPo.setUpdateTime(now);
            this.beanMapper.updateById(havPo);
        }
        CropAreaPo cropAreaPo = new CropAreaPo();
        String cropId = dto.getCrops();
        if(StrUtil.isNotBlank(cropId)){
            cropAreaPo.setAreaId(dto.getId());
            cropAreaPo.setCropId(Integer.parseInt(cropId));
            this.beanMapper.insert(cropAreaPo);
        }
        return this.areaPage(1);
    }

    @Override
    public ModelAndView getDrawPage(Integer id) {
        AreaPo area = this.beanMapper.selectOne(AreaPo.class, String.format("id = %d", id));
        String useStatus = this.baseMapper.getTcCodeBuValue(Integer.parseInt(area.getUseStatus()));
        area.setUseStatus(useStatus);
        return CommonUtil.success("gldraw.html", area);
    }

    @Override
    public ModelAndView messagePage(Integer pageNum) {
        List<MessagePo> list = this.beanMapper.selectList(MessagePo.class, "is_delete = 103001");
        list = list.stream().peek(po -> {
            String reader = po.getReader();
            if(StrUtil.isNotBlank(reader)){
                po.setReader(this.beanMapper.selectList(UserPo.class, String.format("id in (%s)", reader))
                        .stream().map(UserPo::getUsername).collect(Collectors.joining(",")));
            }
        }).collect(Collectors.toList());
        return CommonUtil.successSelect("glmessage.html", list, pageNum);
    }

    @Override
    public ModelAndView deleteMessage(String id, Integer pageNum) {
        this.baseMapper.update(String.format("update tm_message set is_delete = 103002 where id = %s", id));
        return this.areaPage(pageNum);
    }

    @Override
    public ModelAndView editMessage(String id) {
        return CommonUtil.success("editMessage.html", StrUtil.isBlank(id) ? new MessagePo() : this.beanMapper.selectOne(MessagePo.class, String.format("id = %s", id)));
    }

    @Override
    public ModelAndView saveMessage(MessagePo messagePo) {
        UserPo userPo = CommonUtil.getUser();
        LocalDateTime now = LocalDateTime.now();
        messagePo.setIsDelete(103001);
        if(Objects.isNull(messagePo.getId())){
            messagePo.setIssueTime(now);
            messagePo.setIssuer(CommonUtil.getUser().getUsername());
            messagePo.setCreateBy(userPo.getUsername());
            messagePo.setCreateTime(now);
            this.beanMapper.insert(messagePo);
        }else{
            MessagePo havPo = this.beanMapper.selectOne(MessagePo.class, String.format("id = %s", messagePo.getId()));
            havPo.setMessage(messagePo.getMessage());
            havPo.setUpdateBy(userPo.getUsername());
            havPo.setUpdateTime(now);
            this.beanMapper.updateById(havPo);
        }
        return this.messagePage(1);
    }

    @Override
    public ModelAndView cropTypePage(Integer pageNum, Integer typeCode) {
        List<CropTypePo> type = this.beanMapper.selectList(CropTypePo.class, "is_delete = 103001");
        List<CropsPo> crop = this.beanMapper.selectList(CropsPo.class);
        List<TcCodeDto> dic = this.baseMapper.getTcCode(107);
        List<CropTypeDto> res = type.stream().map(po -> {
            CropTypeDto dto = new CropTypeDto();
            BeanUtils.copyProperties(po, dto);
            dto.setTypeCode(107001);
            dto.setType(CommonUtil.getTcCodeValue(dic, dto.getTypeCode()));
            return dto;
        }).collect(Collectors.toList());
        res.addAll(crop.stream().map(po -> {
            CropTypeDto dto = new CropTypeDto();
            BeanUtils.copyProperties(po, dto);
            dto.setTypeCode(107002);
            dto.setCreateTime(CommonUtil.formatLocalDateTime(po.getCreateTime()));
            dto.setType(type.stream().filter(t -> t.getTypeId().equals(po.getTId())).findFirst().orElse(new CropTypePo()).getName());
            dto.setTypeId(po.getId());
            return dto;
        }).collect(Collectors.toList()));
        Map<String, Object> result = new HashMap<>(8);
        if(Objects.nonNull(typeCode)){
            res = res.stream().filter(dto -> dto.getTypeCode().equals(typeCode)).collect(Collectors.toList());
        }
        result.put("data", Objects.isNull(pageNum) ? new Page<>(res) : new Page<>(pageNum, res));
        result.put("dic", dic);
        result.put("type", typeCode);
        return CommonUtil.success("glCropType", result);
    }

    @Override
    public ModelAndView deleteTypePage(String id, Integer pageNum, Integer type) {
        if(type.equals(107001)){
            Integer i = this.baseMapper.selectId(String.format("select 1 from tm_crops where t_id = %s limit 1", id));
            if(Objects.isNull(i)){
                this.baseMapper.update(String.format("update tm_crop_type set is_delete = 103002 where type_id = %s", id));
            }else{
                throw new ServiceException("删除失败：此植物大类有子植物！！！");
            }
        }else{
            Integer i = this.baseMapper.selectId(String.format("select 1 from tm_audit where is_delete = 103001 and crops_id = %s limit 1", id));
            Integer j = this.baseMapper.selectId(String.format("select 1 from tm_plant where crops_id = %s limit 1", id));
            if(Objects.isNull(i) && Objects.isNull(j)){
                this.baseMapper.delete(String.format("delete from tm_crops where id = %s", id));
            }else{
                throw new ServiceException("删除失败：此植物已经被用户申请或种植！！！");
            }
        }
        return this.cropTypePage(pageNum, null);
    }

    @Override
    public ModelAndView editTypePage(String id, Integer type) {
        Map<String, Object> res = new HashMap<>(2);
        CropTypePo po = StrUtil.isBlank(id) ? new CropTypePo() : this.beanMapper.selectOne(CropTypePo.class, String.format("type_id = %s", id));
        res.put("data", po);
        res.put("type", type);
        return CommonUtil.success("editCropType.html", res);
    }

    @Override
    public ModelAndView saveCropType(CropsTypeDto cropsTypeDto) {
        String image = CommonUtil.upload(this.guanliManager.getFilePath(), cropsTypeDto.getImage());
        Integer id = cropsTypeDto.getTypeId(), type = cropsTypeDto.getType();
        if(type.equals(107001)){
            this.guanliManager.saveCropType(id, image, cropsTypeDto);
        }else{
            this.guanliManager.saveCrops(id, image, cropsTypeDto);
        }
        return this.cropTypePage(1, type);
    }

    @Override
    public ModelAndView userPage(Integer pageNum) {
        return CommonUtil.successSelect("gluser.html", this.beanMapper.selectList(UserPo.class, "is_delete = 103001"), pageNum);
    }

    @Override
    public ModelAndView deleteUser(String id, Integer pageNum) {
        UserPo user = this.beanMapper.selectOne(UserPo.class, String.format("id = %s", id));
        user.setIsDelete(103002);
        user.setUpdateBy(CommonUtil.getUser().getUsername());
        user.setUpdateTime(LocalDateTime.now());
        this.beanMapper.updateById(user);
        return this.userPage(pageNum);
    }

    @Override
    public ModelAndView addUser(String id) {
        return CommonUtil.success("editUser.html", null);
    }

    @Override
    public ModelAndView saveUser(UserDto userDto) {
        UserPo user = CommonUtil.getUser();
        LocalDateTime now = LocalDateTime.now();
        Integer id = userDto.getId();
        UserPo userPo = new UserPo();
        if(Objects.isNull(id)){
            String loginId = userDto.getLoginId(), password = Constant.INIT_PASSWORD.getMessage();
            if(Objects.nonNull(this.beanMapper.selectOne(UserPo.class, String.format("login_id = '%s' and is_delete = 103001", loginId)))){
                throw new ServiceException(String.format("该账号：%s已存在，请换一账号！！！", loginId));
            }
            BeanUtils.copyProperties(userDto, userPo);
            userPo.setIsDelete(103001);
            userPo.setUsername(Constant.NEW_USER.getMessage());
            userPo.setPassword(CommonUtil.encryptStr(password));
            userPo.setRealPassword(password);
            userPo.setCreateTime(now);
            userPo.setCreateBy(user.getUsername());
            userPo.setIsVip("101002");
            this.beanMapper.insert(userPo);
        }else{
            userPo = this.beanMapper.selectOne(UserPo.class, String.format("id = %s", id));
            userPo.setIsVip("101001");
            userPo.setUpdateTime(now);
            userPo.setUpdateBy(user.getUsername());
            this.beanMapper.updateById(userPo);
        }
        return this.userPage(1);
    }

    @Override
    public ModelAndView medicinePage(Integer pageNum, Integer medicineId, Integer useStatus) {
        StringBuilder whereSql = new StringBuilder("is_delete = 103001");
        if(Objects.nonNull(medicineId)){
            whereSql.append(" and id = ");
            whereSql.append(medicineId);
        }
        if(Objects.nonNull(useStatus)){
            whereSql.append(" and use_status = ");
            whereSql.append(useStatus);
        }
        List<MedicinePo> list = this.beanMapper.selectList(MedicinePo.class, whereSql.toString());
        List<TcCodeDto> dic = this.baseMapper.getTcCode(104);
        list = list.stream().peek(po -> po.setUseStatus(CommonUtil.getTcCodeValue(dic, Integer.parseInt(po.getUseStatus())))).collect(Collectors.toList());
        Map<String, Object> res = new HashMap<>();
        res.put("medis", Objects.isNull(pageNum) ? new Page<>(list) : new Page<>(pageNum, list));
        res.put("dic", dic);
        res.put("medicineId", medicineId);
        res.put("useStatus", useStatus);
        return CommonUtil.success("glmedicine.html", res);
    }

    @Override
    public ModelAndView deleteMedicine(String id, Integer pageNum) {
        MedicinePo po = this.beanMapper.selectOne(MedicinePo.class, String.format("id = %s", id));
        po.setIsDelete(103002);
        po.setUpdateBy(CommonUtil.getUser().getUsername());
        po.setUpdateTime(LocalDateTime.now());
        this.beanMapper.updateById(po);
        return this.medicinePage(pageNum, null, null);
    }

    @Override
    public ModelAndView editMedicine(Integer id) {
        Map<String, Object> res = new HashMap<>(2);
        res.put("types", this.baseMapper.getTcCode(104));
        MedicinePo medicinePo = Objects.isNull(id) ? new MedicinePo() :this.beanMapper.selectOne(MedicinePo.class, String.format("id = %s", id));
        res.put("target", medicinePo);
        return CommonUtil.success("editMedicine.html", res);
    }

    @Override
    public ModelAndView saveMedicine(MedicineDto dto) {
        UserPo user = CommonUtil.getUser();
        LocalDateTime now = LocalDateTime.now();
        Integer id = dto.getId();
        MedicinePo po = new MedicinePo();
        po.setIsDelete(103001);
        if(Objects.isNull(id)){
            BeanUtils.copyProperties(dto, po);
            po.setCreateBy(user.getUsername());
            po.setCreateTime(now);
            po.setEnableSize(dto.getStockSize());
            po.setUsedSize(0.0);
            po.setUseStatus(String.valueOf(dto.getUseStatus()));
            this.beanMapper.insert(po);
        }else{
            po = this.beanMapper.selectOne(MedicinePo.class, String.format("id = %d", id));
            Double size = dto.getStockSize();
            po.setStockSize(size);
            po.setUnit(dto.getUnit());
            po.setUseStatus(String.valueOf(dto.getUseStatus()));
            po.setUpdateBy(user.getUsername());
            po.setUpdateTime(now);
            po.setEnableSize(size - po.getUsedSize());
            this.beanMapper.updateById(po);
        }
        return this.medicinePage(1, null, null);
    }

    @Override
    public ModelAndView seePage(Integer pageNum, Integer areaId, Integer cropId, Integer plantStatus) {
        List<SeePageDto> list = this.guanliManager.seePage(areaId, cropId, plantStatus);
        Map<String, Object> res = new HashMap<>(8);
        res.put("see", Objects.isNull(pageNum) ? new Page<>(list) : new Page<>(pageNum, list));
        res.put("areaId", areaId);
        res.put("cropId", cropId);
        res.put("plantStatus", plantStatus);
        res.put("dic", this.baseMapper.getTcCode(106));
        res.put("types",  this.beanMapper.selectList(CropsPo.class));
        res.put("areas", this.beanMapper.selectList(AreaPo.class, "is_delete = 103001"));
        return CommonUtil.success("glsee.html", res);
    }
}
